
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
			      console.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
						    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

/*
	回车键: 把光标移到第一列
	换行键: 把光标前进到下一行
*/


#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "keyboard.h"
#include "proto.h"

PRIVATE void set_cursor(unsigned int position);
PRIVATE void set_video_start_addr(u32 addr);
PRIVATE void flush(CONSOLE* p_con);

extern int Fmode;

// 记录所有的TAB和Enter键位的位置
PRIVATE int TabList[256] = {0};
PRIVATE int EnterList[256] = {0};

// 记录当前数组的指向的位置；
PRIVATE int p_Tab = 1;
PRIVATE int p_Enter = 1;

// 将当前光标位置插入TabList数组中
PRIVATE void addTab(int curPos);
PRIVATE void addEnter(int curPos, int dis);
PRIVATE int EnterDis[256] = {0}; // 记录Enter的移动距离

// 用于判断当前光标是否为Tab，如果是，返回1，否则返回0
PRIVATE int isTab(int curPos);
PRIVATE int isEnter(int curPos);


PRIVATE void doDelTab();
PRIVATE void doDelEnter();

// 查找模式下输入的字符长度。
PRIVATE int startPos = 0;
PRIVATE int overPos = 0;
PRIVATE int lenOffind = 0;

/*======================================================================*
			   init_screen
 *======================================================================*/
PUBLIC void init_screen(TTY* p_tty)
{
	int nr_tty = p_tty - tty_table;
	p_tty->p_console = console_table + nr_tty;

	int v_mem_size = V_MEM_SIZE >> 1;	/* 显存总大小 (in WORD) */

	int con_v_mem_size                   = v_mem_size / NR_CONSOLES;
	p_tty->p_console->original_addr      = nr_tty * con_v_mem_size;
	p_tty->p_console->v_mem_limit        = con_v_mem_size;
	p_tty->p_console->current_start_addr = p_tty->p_console->original_addr;

	/* 默认光标位置在最开始处 */
	p_tty->p_console->cursor = p_tty->p_console->original_addr;

	if (nr_tty == 0) {
		/* 第一个控制台沿用原来的光标位置 */
		p_tty->p_console->cursor = disp_pos / 2;
		disp_pos = 0;
	}
	else {
		out_char(p_tty->p_console, nr_tty + '0');
		out_char(p_tty->p_console, '#');
	}

	set_cursor(p_tty->p_console->cursor);
}


/*======================================================================*
			   is_current_console
*======================================================================*/
PUBLIC int is_current_console(CONSOLE* p_con)
{
	return (p_con == &console_table[nr_current_console]);
}


/*======================================================================*
			   out_char
 *======================================================================*/
PUBLIC void out_char(CONSOLE* p_con, char ch)
{
	u8* p_vmem = (u8*)(V_MEM_BASE + p_con->cursor * 2);

	int startPos;
	int dis;

	int deleteSucceed = 1;
	
	switch(ch) {
	case '\n':
		startPos = p_con->cursor;
		if (p_con->cursor < p_con->original_addr +
		    p_con->v_mem_limit - SCREEN_WIDTH) {
			p_con->cursor = p_con->original_addr + SCREEN_WIDTH * 
				((p_con->cursor - p_con->original_addr) /
				 SCREEN_WIDTH + 1);
		}
		dis = p_con->cursor - startPos; // 记录了指针移动的长度;
		addEnter(p_con->cursor, dis);
		break;

	case '\t': // TAB
		for(int i = 0;i < 4;i++){
			out_char(p_con, ' ');
		}

		addTab(p_con->cursor);
		if(Fmode==1){
			lenOffind -= 3;
		}
		break;

	case '\b': // Backspace
		if (p_con->cursor > p_con->original_addr) {
			deleteSucceed = 1;
			if (isTab(p_con->cursor)){
				for (int i=0;i<4;i++){
					p_con->cursor--;
					*(p_vmem-2) = ' ';
					*(p_vmem-1) = DEFAULT_CHAR_COLOR;
				}
				doDelTab();
			} // Over
			else if (isEnter(p_con->cursor))
			{
				int distance = EnterDis[p_Enter - 1];
				for (int i=0;i<distance;i++){
					p_con->cursor--;
					*(p_vmem-2) = ' ';
					*(p_vmem-1) = DEFAULT_CHAR_COLOR;
				}
				doDelEnter();
			}
			else{
				p_con->cursor--;
				*(p_vmem-2) = ' ';
				*(p_vmem-1) = DEFAULT_CHAR_COLOR;
			}
			if (Fmode == 1){
				lenOffind--;
			}
		}
		break;


	default:
		if (p_con->cursor <
		    p_con->original_addr + p_con->v_mem_limit - 1) {
			*p_vmem++ = ch;
			if (Fmode == 0){
				*p_vmem++ = DEFAULT_CHAR_COLOR;
			}
			else {
				*p_vmem++ = SPECIAL_CHAR_COLOR;
				lenOffind++;
			}
			p_con->cursor++;
		}

		break;
	}

	while (p_con->cursor >= p_con->current_start_addr + SCREEN_SIZE) {
		scroll_screen(p_con, SCR_DN);
	}

	flush(p_con);
}

/*======================================================================*
                           flush
*======================================================================*/
PRIVATE void flush(CONSOLE* p_con)
{
        set_cursor(p_con->cursor);
        set_video_start_addr(p_con->current_start_addr);
}

/*======================================================================*
			    set_cursor
 *======================================================================*/
PRIVATE void set_cursor(unsigned int position)
{
	disable_int();
	out_byte(CRTC_ADDR_REG, CURSOR_H);
	out_byte(CRTC_DATA_REG, (position >> 8) & 0xFF);
	out_byte(CRTC_ADDR_REG, CURSOR_L);
	out_byte(CRTC_DATA_REG, position & 0xFF);
	enable_int();
}

/*======================================================================*
			  set_video_start_addr
 *======================================================================*/
PRIVATE void set_video_start_addr(u32 addr)
{
	disable_int();
	out_byte(CRTC_ADDR_REG, START_ADDR_H);
	out_byte(CRTC_DATA_REG, (addr >> 8) & 0xFF);
	out_byte(CRTC_ADDR_REG, START_ADDR_L);
	out_byte(CRTC_DATA_REG, addr & 0xFF);
	enable_int();
}



/*======================================================================*
			   select_console
 *======================================================================*/
PUBLIC void select_console(int nr_console)	/* 0 ~ (NR_CONSOLES - 1) */
{
	if ((nr_console < 0) || (nr_console >= NR_CONSOLES)) {
		return;
	}

	nr_current_console = nr_console;

	set_cursor(console_table[nr_console].cursor);
	set_video_start_addr(console_table[nr_console].current_start_addr);
}

/*======================================================================*
			   scroll_screen
 *----------------------------------------------------------------------*
 滚屏.
 *----------------------------------------------------------------------*
 direction:
	SCR_UP	: 向上滚屏
	SCR_DN	: 向下滚屏
	其它	: 不做处理
 *======================================================================*/
PUBLIC void scroll_screen(CONSOLE* p_con, int direction)
{
	if (direction == SCR_UP) {
		if (p_con->current_start_addr > p_con->original_addr) {
			p_con->current_start_addr -= SCREEN_WIDTH;
		}
	}
	else if (direction == SCR_DN) {
		if (p_con->current_start_addr + SCREEN_SIZE <
		    p_con->original_addr + p_con->v_mem_limit) {
			p_con->current_start_addr += SCREEN_WIDTH;
		}
	}
	else{
	}

	set_video_start_addr(p_con->current_start_addr);
	set_cursor(p_con->cursor);
}

// // 记录所有的TAB和Enter键位的位置
// int TabList[256];
// int EnterList[256];
// // 记录当前数组的长度；
// int p_Tab = 0;
// int p_Enter = 0;

// // 将当前光标位置插入TabList数组中
// void addTab(int curPos);
// void addEnter(int curPos, int dis);
// int EnterDis[256]; // 记录Enter的移动距离

void addTab(int curPos){
	TabList[p_Tab] = curPos;
	p_Tab++;

}
void addEnter(int curPos, int dis){
	EnterList[p_Enter] = curPos;
	EnterDis[p_Enter] = dis;
	p_Enter++;
}

int isTab(int curPos){
	if(curPos==TabList[p_Tab - 1]){
		return 1;
	}
	return 0;
}

int isEnter(int curPos){
	if(curPos==EnterList[p_Enter - 1]){
		return 1;
	}
	return 0;
}

void doDelTab(){
	TabList[p_Tab] = 0;
	p_Tab--;
}
void doDelEnter(){
	EnterList[p_Enter] = 0;
	EnterDis[p_Enter] = 0;
	p_Enter--;
}

PUBLIC void start_find(){
	lenOffind = 0;
}


PUBLIC void stop_find(CONSOLE* p_con){
    //恢复字体颜色并输入删除所有查询字符
    u8* p_vmem = (u8*)(V_MEM_BASE + p_con->cursor * 2);
    for(int i=0;i<p_con->cursor-p_con->original_addr;i++){
        if(*(p_vmem-2*i-1)==SPECIAL_CHAR_COLOR){
            *(p_vmem-2*i-1)=DEFAULT_CHAR_COLOR;
        }
    }

    for(int i=0;i<lenOffind;i++){
    	out_char(p_con,'\b');
	}
}


PUBLIC void find(CONSOLE* p_con){

	int  findptr=0;
	int c_search = p_con->cursor;
	u8* p_vmem = (u8*)(V_MEM_BASE + p_con->cursor * 2);

	// 记录查找字符串的总长
    for(int i=0;i<p_con->cursor-p_con->original_addr;i++){
        if(*(p_vmem-2*i-1)==SPECIAL_CHAR_COLOR){
            findptr++;
        }

    }

	int k = findptr;

	int c_real = p_con->cursor - findptr;

    for(int i=k;i<p_con->cursor-p_con->original_addr;i++){
    	int temp=1;
		for(int j=0;j<k;j++){
			char ch_search = ((u8*)(V_MEM_BASE + (c_search - j) * 2)) - 2; // 搜索字符
			out_char(p_con, '|');
			out_char(p_con, ch_search);
			out_char(p_con, '|');
			char ch_real = ((u8*)(V_MEM_BASE + (c_real - i - j) * 2)) - 2; // 被搜索字符
			out_char(p_con, '|');
			out_char(p_con, ch_real);
			out_char(p_con, '|');
			if(ch_search != ch_real){
				temp=0;
				break;
			}
			else if(isTab(c_search-j)!=isTab(c_real-i-j)){
				temp = 0;
				break;
			}
		}
		 
		if(temp==1){
			for(int j=0;j<findptr;j++){
				*(p_vmem-2*j-2*i-1)=SPECIAL_CHAR_COLOR;
			}
		}
    }

}